#!/usr/bin/python2.4
#
# Copyright 2008 Google Inc.
# 
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
# 
#      http://www.apache.org/licenses/LICENSE-2.0 
# 
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""upload page."""

import logging
import os
import re
import gdata.service
import gdata.urlfetch
# Use urlfetch instead of httplib
gdata.service.http_request_handler = gdata.urlfetch
from google.appengine.api import urlfetch
from google.appengine.api import users
from google.appengine.ext import webapp
from google.appengine.ext.webapp import template
from google.appengine.ext.webapp.util import login_required
import instantvidsite
import browse
import wsgiref.handlers


class ProcessAuthSubResponse(webapp.RequestHandler):

  """receive the authsub redirect after access is granted."""
  
  def get(self, sitepath):
    
    """receive the authsub redirect after access is granted."""
    
    #find domain
    site = instantvidsite.GetSite(sitepath)
    if not site:
      logging.error('bad sitepath - '+str(sitepath))
      self.redirect("/?error=siteunknown")
      return
    
    session_token = self.request.get('token')
    #logging.debug('received token: '+session_token)
                    
    #convert tmp token to session token

#    pygdata version - freshly implemented
    service = gdata.service.GDataService()
    service.SetAuthSubToken(session_token)
    service.UpgradeToSessionToken()
    session_token = service.GetAuthSubToken()
    #logging.debug('token upgraded to: '+session_token)

#    fetch_result = urlfetch.Fetch('https://www.google.com/accounts/AuthSubSessionToken', 
#                                  method=urlfetch.GET, 
#                                  headers={'Authorization': BuildAuthHeader(session_token) })

#    logging.debug('token upgrade response status: '+str(fetch_result.status_code))
#    logging.debug('token upgrade response content:\n '+fetch_result.content)    

    #TODO(gabe): error handling

#    m=re.search('Token=(.*)', fetch_result.content)
#    session_token = m.group(1)    

    #store session token
    user = browse.GetTubeUser(site)
    if user is None:
      user = instantvidsite.TubeUser()
      user.user = users.GetCurrentUser()
      user.site = site.key()
    user.auth_token = session_token
    user.put()
   
    #redirect to video upload page
    self.redirect('/a/'+site.path+'/upload/UploadVideo')


class UploadVideoMetadata(webapp.RequestHandler):

  """prompt user for video metadata to get upload token."""
  
  @login_required
  def get(self, sitepath):
    
    """prompt user for video metadata."""
    
    #find domain
    site = instantvidsite.GetSite(sitepath)
    if not site:
      logging.error('bad sitepath - '+str(sitepath))
      self.redirect("/?error=siteunknown")
      return
      
    # check for existing token
    session_token = browse.GetAuthSubToken()
    
    # if no token, redirect to authsub url
    if session_token is None:
      service = gdata.service.GDataService()
      authurl = service.GenerateAuthSubURL("http://"+os.environ['SERVER_NAME']+':'+os.environ['SERVER_PORT']+"/a/"+site.path+"/upload/AuthSubDone",
                                           "http://gdata.youtube.com")
      #logging.debug("authsub request url"+authurl)
      self.redirect(authurl)
      return
                                   
    # display metadata form    
    browse.PrintHeader(self.request, self.response, site, 
                         site.display_name + ' - specify video properties')

    path = os.path.join(os.path.dirname(__file__), 'metadata.html')
    self.response.out.write(template.render(path, {'site': site}))

  def post(self, sitepath):
    
    """use metadata to generate upload token."""
    
    #find domain
    site = instantvidsite.GetSite(sitepath)
    if not site:
      logging.error('bad sitepath - '+str(sitepath))
      self.redirect("/?error=siteunknown")
      return

    user = users.GetCurrentUser()
    loggedin = user is not None
    
    if not loggedin:
      self.redirect(users.CreateLoginURL(self.request.uri))
      return

    #construct metadata XML from post params

    video_title = self.request.get('title')
    video_tags = self.request.get('tags').strip().replace(' ',',')
    video_description = self.request.get('description')

    #add user option for private videos?
    #TODO(gabe): fix developer tag to be truncated db key
    video_metadata = '''

<entry xmlns="http://www.w3.org/2005/Atom"
  xmlns:media="http://search.yahoo.com/mrss/"
  xmlns:yt="http://gdata.youtube.com/schemas/2007">
  <media:group>
    <media:title type="plain">%(title)s</media:title>
    <media:description type="plain">from %(site_name)s - %(desc)s</media:description>
    <media:category scheme="http://gdata.youtube.com/schemas/2007/categories.cat">Autos</media:category>
    <media:category scheme="http://gdata.youtube.com/schemas/2007/developertags.cat">%(site_key)s</media:category>
    <media:keywords>%(site_tag)s,%(tags)s</media:keywords>
  </media:group>
</entry>
''' % {'title': video_title, 'desc': video_description, 'tags': video_tags,
       'site_tag': site.path, 'site_name': site.display_name, 'site_key': site.path}
   
    #grab token from store
    token = browse.GetAuthSubToken()
    
    if token is None:
      self.redirect('/a/'+site.path+'/upload/UploadVideo')
      return
    
    video_metadata_post_headers = {'Authorization':
                                   browse.BuildAuthHeader(token),
                                   'X-GData-Key': ('key=' + browse.youtube_key),
                                   'Content-Type': 'application/atom+xml; charset=UTF-8'}

    #TODO(gabe): fix this URL when current response is deprecated
    fetch_result = urlfetch.Fetch('http://gdata.youtube.com/action/GetUploadToken',
                                  method=urlfetch.POST,
                                  headers=video_metadata_post_headers,
                                  payload=video_metadata)
    
    #logging.debug('get upload token response code - '+str(fetch_result.status_code))
    #logging.debug(fetch_result.headers)
    #logging.debug(fetch_result.content)

    #handle bad status codes
    if fetch_result.status_code > 201 or fetch_result.status_code < 200:
      logging.error(fetch_result.headers)
      logging.error(fetch_result.content)
      self.redirect('/?error=gettokenfailed')      
      return

    #parse out upload url and token
    #logging.debug(fetch_result.content)
    
    m = re.search('<url>([^<]*)<', fetch_result.content)
    if not m:
      logging.error(fetch_result.content)
      self.redirect('/?error=gettokenfailed')
      return
    post_url = m.group(1)
    print post_url
    
    m = re.search('token>([^<]*)<', fetch_result.content)
    if not m:
      logging.error(fetch_result.content)
      self.redirect('/?error=gettokenfailed')
      return
    upload_token = m.group(1)

    #TODO(gabe): - generate and store a 1-time use key to embed in the return url - which helps us get metadata back easily too    
    
    actionurl = (post_url + '?nexturl=http%3A%2F%2F' + 
      os.environ['SERVER_NAME'] + '%3A' + os.environ['SERVER_PORT'] +
      '/a/'+site.path+'/upload/VideoPosted')
            
    # display upload form
    template_values = {'actionurl': actionurl,
                       'token': upload_token}

    browse.PrintHeader(self.request, self.response, site, 
                         site.display_name + ' - specify video file')

    path = os.path.join(os.path.dirname(__file__), 'upload.html')
    self.response.out.write(template.render(path, template_values))


class ProcessVideoResponse(webapp.RequestHandler):
  
  """take video upload response code and store video info."""
  
  @login_required
  def get(self, sitepath):
    
    """get method."""
    
    #find domain
    site = instantvidsite.GetSite(sitepath)
    if not site:
      logging.error('bad sitepath - '+str(sitepath))
      self.redirect("/?error=siteunknown")
      return
    
    upload_status = self.request.get('status')
    video_id = self.request.get('id')

    #check status
    if upload_status != '200':
      #self.response.out.write('<p>'+str(fetch_result.content))
      #self.redirect('/?error='+UPLOAD_FAILED)
      return 
    
    #store video id record   
    video_record = instantvidsite.Video()
    video_record.user = users.GetCurrentUser()
    video_record.id = self.request.get('id')
    video_record.status = 'unknown'
    video_record.site = site.key()
    video_record.put()
    
    # display success page
    template_values = {'id': video_id}

    browse.PrintHeader(self.request, self.response, site,
                         site.display_name + ' - video uploaded!')  

    path = os.path.join(os.path.dirname(__file__), 'success.html')
    self.response.out.write(template.render(path, template_values))


def main():
  application = webapp.WSGIApplication([(r'/a/([^/]*)/upload/AuthSubDone',
                                         ProcessAuthSubResponse),
                                         (r'/a/([^/]*)/upload/VideoPosted',
                                          ProcessVideoResponse),
                                          (r'/a/([^/]*)/upload/UploadVideo',
                                           UploadVideoMetadata)], debug=False)

  logging.getLogger().setLevel(logging.DEBUG)
  wsgiref.handlers.CGIHandler().run(application)

if __name__ == '__main__':
  main()
